package com.template.utils.redis;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.*;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.GeoOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.domain.geo.Metrics;
import org.springframework.stereotype.Component;

import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Component
public class GeoOps extends KeyOps {

    private final GeoOperations<String, Object> geoOperations;

    @Autowired
    public GeoOps(RedisTemplate<String, Object> redisTemplate) {
        super(redisTemplate);
        this.geoOperations = redisTemplate.opsForGeo();
    }

    /**
     * <h4> GEO </h4>
     * 添加经纬度坐标
     * <li> geoadd _key _longitude _latitude _name </li>
     *
     * @param longitude 经度
     * @param latitude  纬度
     * @param name      地理名称
     */
    public Long geoAdd(String key, double longitude, double latitude, Object name) {
        return geoOperations.add(key, new Point(longitude, latitude), name);
    }

    /**
     * <h4> GEO </h4>
     * 批量添加经纬度坐标
     * <li> geoadd _key _longitude1 _latitude1 _name1 _longitude2 _latitude2 _name2 </li>
     */
    public Long geoAdd(String key, Map<Object, Point> memberCoordinateMap) {
        return geoOperations.add(key, memberCoordinateMap);
    }

    /**
     * <h4> GEO </h4>
     * 批量返回经纬度
     * <li> geopos _key _member1 _member2 ... </li>
     */
    public Point geoPos(String key, Object member) {
        List<Point> points = Objects.requireNonNull(geoOperations.position(key, member));
        return points.size() == 0 ? null : points.get(0);
    }

    /**
     * <h4> GEO </h4>
     * 批量返回经纬度
     * <li> geopos _key _member1 _member2 ... </li>
     */
    public List<Point> geoPos(String key, Object... members) {
        return geoOperations.position(key, members);
    }

    /**
     * <h4> GEO </h4>
     * 批量返回经纬度
     * <li> geopos _key _member1 _member2 ... </li>
     */
    public List<Point> geoPos(String key, Collection<Object> members) {
        return geoOperations.position(key, members.toArray());
    }

    /**
     * <h4> GEO </h4>
     * 批量返回经纬度，以 geohash 表示（以某种算法将一个经纬度以字符串表示）
     * <li> geohash _key _member1 _member2 ... </li>
     */
    public String geoHash(String key, Object member) {
        List<String> hash = geoOperations.hash(key, member);
        return hash == null || hash.size() == 0 ? null : hash.get(0);
    }

    /**
     * <h4> GEO </h4>
     * 批量返回经纬度，以 geohash 表示（以某种算法将一个经纬度以字符串表示）
     * <li> geohash _key _member1 _member2 ... </li>
     */
    public List<String> geoHash(String key, Object... members) {
        return geoOperations.hash(key, members);
    }

    /**
     * <h4> GEO </h4>
     * 批量返回经纬度，以 geohash 表示（以某种算法将一个经纬度以字符串表示）
     * <li> geohash _key _member1 _member2 ... </li>
     */
    public List<String> geoHash(String key, Collection<Object> members) {
        return geoOperations.hash(key, members.toArray());
    }

    /**
     * <h4> GEO </h4>
     * 获取两个给定位置之间的距离
     * <li> georadius _key _member1 _member2 ... </li>
     */
    public Distance geoDist(String key, Object member1, Object member2, Metrics metric) {
        return geoOperations.distance(key, member1, member2, metric);
    }

    /**
     * <h4> GEO </h4>
     * 获取两个给定位置之间的距离
     * <li> georadius _key _member1 _member2 ... </li>
     */
    @Deprecated
    public GeoResults<RedisGeoCommands.GeoLocation<Object>> geoRadius(String key, Circle within) {
        return geoOperations.radius(key, within);
    }

    /**
     * <h4> GEO </h4>
     * 获取两个给定位置之间的距离
     * <li> geosearch _key _member1 _member2 ... </li>
     */
    public GeoResults<RedisGeoCommands.GeoLocation<Object>> geoSearch(String key, Circle within) {
        return geoOperations.search(key, within);
    }
}
